package com.na.report.utils;

import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.util.Arrays;

public class ByteArrayStream extends InputStream {

	private byte[] buf;
	private int count; // write start pos(read limit)
	private int pos; // read start pos
	private int mark; // mark pos
	
	// read
	public ByteArrayStream(byte[] buf) {
		this(buf, 0, buf.length);
	}
	
	public ByteArrayStream(byte[] buf, int offset, int length) {
		this.buf = buf;
		this.pos = offset;
		this.count = Math.min(offset + length, buf.length);
		this.mark = offset;
	}
	
	// write
	public ByteArrayStream() {
		this(512);
	}
	
	public ByteArrayStream(int capacity) {
		if (capacity < 0) {
			throw new IllegalArgumentException("capacity < 0: " + capacity);
		}
		buf = new byte[capacity];
	}
	
	// read methods
	@Override
	public int read()/* throws IOException*/ {
		return (pos < count) ? (buf[pos++] & 0xff) : -1;
	}
	
	@Override
	public int read(byte[] b, int off, int len)/* throws IOException*/ {
		if (b == null) {
            throw new NullPointerException();
        }
		if (off < 0 || len < 0 || len > b.length - off) {
            throw new IndexOutOfBoundsException();
        }

        if (pos >= count) {
            return -1;
        }

        int avail = count - pos;
        if (len > avail) {
            len = avail;
        }
        if (len <= 0) {
            return 0;
        }
        System.arraycopy(buf, pos, b, off, len);
        pos += len;
        return len;
	}

	@Override
	public long skip(long n)/* throws IOException*/ {
		long k = count - pos;
        if (n < k) {
            k = n < 0 ? 0 : n;
        }
        pos += k;
        return k;
	}

	@Override
	public int available()/* throws IOException*/ {
		return count - pos;
	}

	@Override
	public void close()/* throws IOException*/ {
	}

	@Override
	public void mark(int readlimit) {
		mark = pos;
	}

	@Override
	public void reset()/* throws IOException*/ {
		pos = mark;
	}

	@Override
	public boolean markSupported() {
		return true;
	}

	// write methods
	public void write(int b) {
		ensureCapacity(count + 1);
		buf[count++] = (byte) b;
	}
	
	public void write(byte[] b, int off, int len) {
		ensureCapacity(count + len);
		System.arraycopy(b, off, buf, count, len);
		count += len;
	}
	
	public int write(InputStream src, int len) {
		ensureCapacity(count + len);
		try {
			len = src.read(buf, count, len);
			if (len > 0) {
				count += len;
			}
			return len;
		} catch (IOException e) {
		}
		return 0;
	}
	
	private void ensureCapacity(int newLen) {
		int len = buf.length;
		if (newLen > len) {
			len <<= 1;
			if (len < newLen) {
				len = newLen;
			}
			buf = Arrays.copyOf(buf, len);
		}
	}
	
	@Override
	public String toString() {
		return new String(buf, pos, count);
	}
	
	public String toString(String charset) {
		try {
			return new String(buf, pos, count, charset);
		} catch (UnsupportedEncodingException e) {
		}
		return null;
	}
	
	public byte[] toByteArray() {
		return Arrays.copyOfRange(buf, pos, count);
	}

}
